package de.nak.terminumfrageapp.dao;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import de.nak.terminumfrageapp.model.Benutzer;
import de.nak.terminumfrageapp.model.Rueckmeldung;
import de.nak.terminumfrageapp.model.Termin;
import de.nak.terminumfrageapp.model.Umfrage;

/**
 * 
 * @description Data Access Object fuer @link Rueckmeldung
 * @author Tim Danker
 *
 */
public class RueckmeldungDAO {
	/** Hibernate session factory. */
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * @description laedt eine einzelne Rueckmeldung
	 * @param Id
	 * @return Rueckmeldung
	 */
	public Rueckmeldung laden(Long id) {
		Session currentSession = sessionFactory.getCurrentSession();
		return (Rueckmeldung) currentSession.get(Rueckmeldung.class, id);
	}

	/**
	 * @description speichert eine mitgegebe Rueckmeldung.
	 * @param Rueckmeldung
	 */
	public Rueckmeldung speichern(Rueckmeldung rueckmeldung) {
		Session currentSession = sessionFactory.getCurrentSession();
		currentSession.saveOrUpdate(rueckmeldung);
		return rueckmeldung;

	}

	/**
	 * @description loescht eine Rueckmeldung.
	 * @param Rueckmeldung
	 */
	public void loeschen(Rueckmeldung rueckmeldung) {
		Session currentSession = sessionFactory.getCurrentSession();
		currentSession.delete(rueckmeldung);
	}

	/**
	 * @description laedt eine Rueckmeldung.
	 * @param Id
	 */
	public Rueckmeldung ladeRueckmeldung(Long id) {
		Session currentSession = sessionFactory.getCurrentSession();
		return (Rueckmeldung) currentSession.get(Rueckmeldung.class, id);
	}

	/**
	 * @description laedt eine Liste von Benutzern mit Zusagen fuer eine
	 *              mitgegeben Umfrage.
	 * @return ArrayList von Benutzern
	 * @param Umfrage
	 *            , Benutzer
	 */
	@SuppressWarnings("unchecked")
	public ArrayList<Benutzer> listeVonBenutzerMitZusage(Umfrage umfrage,
			Benutzer benutzer) {
		Session currentSession = sessionFactory.getCurrentSession();
		Query query = currentSession
				.createQuery("from Rueckmeldung where benutzer.id <>'"
						+ benutzer.getId() + "' and umfrage.id = '"
						+ umfrage.getId() + "' order by umfrage.id");
		// Variablen initialisieren
		ArrayList<Benutzer> benutzerListe = new ArrayList<Benutzer>();
		Rueckmeldung vorigeRueckmeldung = null;
		// Iterator anlegen
		Iterator<Rueckmeldung> iterator = query.list().iterator();
		// durch Ergebnis iterieren
		while (iterator.hasNext()) {

			Rueckmeldung aktuelleRueckmeldung = (Rueckmeldung) iterator.next();
			// beim ersten Durchlauf Benutzer der Rueckmeldung der Liste
			// hinzufuegen
			if (vorigeRueckmeldung == null) {
				benutzerListe.add(aktuelleRueckmeldung.getBenutzer());
			} else {
				// pruefen ob es ein anderer Benutzer als beim letzten Durchlauf
				// ist,
				// wenn ja, der Liste hinzufuegen, ansonsten naechstes Ergebnis
				// pruefen
				if (vorigeRueckmeldung.getBenutzer().getId() != aktuelleRueckmeldung
						.getBenutzer().getId()) {
					benutzerListe.add(aktuelleRueckmeldung.getBenutzer());
				}
			}
			vorigeRueckmeldung = aktuelleRueckmeldung;
		}

		return benutzerListe;
	}

	/**
	 * @description liefert ein Array mit Rueckmeldungen fuer eine Liste von
	 *              Benutzern, eine Liste von Terminen und einen mitgebenen
	 *              Benutzer, der ausgenommen wird von der Rueckgabe.
	 * @return zweidimensionales Array von Rueckmeldungen mit Integer-BenutzerId
	 *         und Integer-TerminId als Dimensionen
	 * @param List
	 *            <Benutzer>, List<Termin>, Benutzer
	 */
	public Rueckmeldung[][] arrayVonRueckmeldungen(
			List<Benutzer> benutzerListe, List<Termin> terminListe,
			Benutzer eigenerBenutzer) {

		// groesste BenutzerId als Integer Wert aus der benutzerListe ermitteln
		int groessteBenutzerId;
		groessteBenutzerId = 1;
		for (Benutzer singleBenutzer : benutzerListe) {
			if (singleBenutzer.getId().intValue() > groessteBenutzerId) {
				groessteBenutzerId = singleBenutzer.getId().intValue();
			}
		}

		// groeeste TerminId als Integer Wert aus der terminListe ermitteln
		int groessteTerminId;
		groessteTerminId = 1;
		for (Termin singleTermin : terminListe) {
			if (singleTermin.getId().intValue() > groessteTerminId) {
				groessteTerminId = singleTermin.getId().intValue();
			}
		}

		// Array dimensionieren mit der groessten BenutzerId und der groeesten
		// TerminId
		// jeweils noch +1 rechnen, damit Dimensionierung passt
		Rueckmeldung[][] rueckmeldungen = new Rueckmeldung[groessteBenutzerId + 1][groessteTerminId + 1];

		Session currentSession = sessionFactory.getCurrentSession();

		// fuer alle Benutzer und Termine Rueckmeldungen laden und ins
		// Array speichern
		for (Benutzer singleBenutzer : benutzerListe) {
			for (Termin singleTermin : terminListe) {
				Query query = currentSession
						.createQuery("from Rueckmeldung where benutzer.id ='"
								+ singleBenutzer.getId()
								+ "' and termin.id = '" + singleTermin.getId()
								+ "'");

				Rueckmeldung einzelneRueckmeldung = (Rueckmeldung) query
						.uniqueResult();
				// IDs muessen zum Speichern wieder in IntValues geaendert
				// werden,
				// damit im Array gespeichert werden kann.
				int nutzerID = singleBenutzer.getId().intValue();
				int termID = singleTermin.getId().intValue();
				rueckmeldungen[nutzerID][termID] = einzelneRueckmeldung;
			}
		}

		return rueckmeldungen;
	}

	/**
	 * @description liefert ein Array mit Rueckmeldungen fuer eine Liste von
	 *              Terminen fuer einen mitgegebenen Benutzer.
	 * @return zweidimensionales Array von Rueckmeldungen mit Integer-BenutzerId
	 *         und Integer-TerminId als Dimensionen
	 * @param Benutzer
	 *            , List<Termin>
	 */
	public Rueckmeldung[][] arrayVonEigenenRueckmeldungen(Benutzer benutzer,
			List<Termin> terminListe) {

		Session currentSession = sessionFactory.getCurrentSession();

		// BenutzerId als Integer Wert ermitteln
		int benutzerId = (int) benutzer.getId().intValue();

		// groeeste TerminId als Integer Wert aus der terminListe ermitteln
		int groessteTerminId;
		groessteTerminId = 1;
		for (Termin singleTermin : terminListe) {
			if (singleTermin.getId().intValue() > groessteTerminId) {
				groessteTerminId = singleTermin.getId().intValue();
			}
		}

		// Array dimensionieren mit der benutzerId und der groeesten terminId
		// jeweils noch +1 rechnen, damit Dimensionierung passt
		Rueckmeldung[][] rueckmeldungsArray = new Rueckmeldung[benutzerId + 1][groessteTerminId + 1];

		// fuer alle Termine die Rueckmeldungen fuer den Benutzer laden
		for (Termin singleTermin : terminListe) {
			Query query = currentSession
					.createQuery("from Rueckmeldung where benutzer.id ='"
							+ benutzer.getId() + "' and termin.id = '"
							+ singleTermin.getId() + "'");

			// IDs muessen zum Speichern wieder in IntValues geaendert werden,
			// damit im Array gespeichert werden kann.
			int terminId = (int) singleTermin.getId().intValue();
			Rueckmeldung einzelneRueckmeldung = (Rueckmeldung) query
					.uniqueResult();
			rueckmeldungsArray[benutzerId][terminId] = einzelneRueckmeldung;
		}
		return rueckmeldungsArray;
	}

	/**
	 * @description erstellt eine Rueckmeldung fuer einen Termin, einen Benutzer
	 *              und eine Umfrage, abhaengig vom mitgebenen Benutzer wird die
	 *              Zusage als true oder false angelegt.
	 * @param Termin
	 *            , Benutzer, Umfrage
	 */
	public void erstelleRueckmeldung(Rueckmeldung rueckmeldung) {

		Session currentSession = sessionFactory.getCurrentSession();
		currentSession.save(rueckmeldung);
	}

	/**
	 * @description prueft, ob der mitgegebene Benutzer fuer einen mitgegebenen
	 *              Termin bereits eine Rueckmeldung hat.
	 * @return Boolean-Wert
	 * @param Benutzer
	 *            , Termin
	 */
	public boolean hatBenutzerRueckmeldung(Benutzer benutzer, Termin termin) {
		Session currentSession = sessionFactory.getCurrentSession();

		Query query = currentSession
				.createQuery("from Rueckmeldung where benutzer.id ='"
						+ benutzer.getId() + "' and termin.id = '"
						+ termin.getId() + "'");
		return query.list().isEmpty();
	}

	/**
	 * @description laedt eine Liste mit Umfragen, fuer die der mitgegebene
	 *              Benutzer bereits eine Rueckmeldung hat.
	 * @return eine Liste mit Umfragen
	 * @param Benutzer
	 */
	@SuppressWarnings("unchecked")
	public List<Umfrage> ladeUmfragenMitRueckmeldung(Benutzer benutzer) {
		Session currentSession = sessionFactory.getCurrentSession();

		// alle Rueckmeldungen fuer den Benutzer laden
		Query query = currentSession
				.createQuery("from Rueckmeldung where benutzer.id ='"
						+ benutzer.getId() + "' order by benutzer.id");

		// Variablen initialisieren
		ArrayList<Umfrage> umfrageListe = new ArrayList<Umfrage>();
		Rueckmeldung vorigeRueckmeldung = null;

		// Iterator anlegen
		Iterator<Rueckmeldung> iterator = query.list().iterator();

		while (iterator.hasNext()) {

			Rueckmeldung aktuelleRueckmeldung = (Rueckmeldung) iterator.next();
			// beim ersten Durchlauf Umfrage der Rueckmeldung der Liste
			// hinzufuegen
			if (vorigeRueckmeldung == null) {
				umfrageListe.add(aktuelleRueckmeldung.getUmfrage());
			} else {
				// pruefen ob es eine andere Umfrage als beim letzten Durchlauf
				// ist,
				// wenn ja, der Liste hinzufuegen, ansonsten naechstes Ergebnis
				// pruefen
				if (vorigeRueckmeldung.getUmfrage().getId() != aktuelleRueckmeldung
						.getUmfrage().getId()) {
					umfrageListe.add(aktuelleRueckmeldung.getUmfrage());
				}
			}
			vorigeRueckmeldung = aktuelleRueckmeldung;
		}
		return umfrageListe;
	}

	/**
	 * @description laedt eine Liste mit Umfragen fuer die mitgegeben Liste von
	 *              (allen) Umfragen fuer die der mitgegebene Benutzer noch
	 *              keine Rueckmeldung hat.
	 * @return eine Liste mit Umfragen
	 * @param Benutzer
	 *            , List<Umfrage>
	 */
	public List<Umfrage> ladeUmfragenOhneRueckmeldung(Benutzer benutzer,
			List<Umfrage> alleUmfragen) {
		Session currentSession = sessionFactory.getCurrentSession();

		// ArrayList initialisieren
		ArrayList<Umfrage> umfrageListe = new ArrayList<Umfrage>();

		// fuer alle Umfragen pruefen ob der Benutzer bereits eine
		// Rueckmeldung hat. Wenn ja, Umfrage der Ausgabe-Liste
		// hinzufuegen
		for (Umfrage singleUmfrage : alleUmfragen) {
			Query query = currentSession
					.createQuery("from Rueckmeldung where benutzer.id ='"
							+ benutzer.getId() + "' and umfrage.id ='"
							+ singleUmfrage.getId() + "'");
			if (query.list().isEmpty() == true) {
				umfrageListe.add(singleUmfrage);
			}
		}

		return umfrageListe;
	}

	/**
	 * @description laedt eine Liste mit Anzahl der Zusagen fuer eine
	 *              mitgegebene Liste von Terminen.
	 * @return ArrayList<Long> mit Anzahl der Zusagen fuer einen Termin
	 * @param List
	 *            <Termin>
	 */
	public ArrayList<Long> ladeAnzahlZusagenProTermin(List<Termin> terminListe) {
		Session currentSession = sessionFactory.getCurrentSession();

		// ArrayList initialisieren
		ArrayList<Long> zusagen = new ArrayList<Long>();

		// fuer alle Termine die Anzahl der Zusagen laden
		for (Termin singleTermin : terminListe) {
			Query query = currentSession
					.createQuery("select count(*) from Rueckmeldung where termin.id ='"
							+ singleTermin.getId() + "' and zusage = true");
			Long result = (Long) query.uniqueResult();

			zusagen.add(result);
		}
		return zusagen;
	}

	/**
	 * @description loescht alle Rueckmeldungen fuer eine mitgebene TerminId.
	 * @param Termin
	 *            -Id
	 */
	@SuppressWarnings("unchecked")
	public void loescheAlleRueckmeldungen(Long ausgewaehlteTerminId) {
		Session currentSession = sessionFactory.getCurrentSession();

		// Alle Rueckmeldung fuer TerminId laden
		Query query = currentSession
				.createQuery("from Rueckmeldung where termin.id ='"
						+ ausgewaehlteTerminId + "'");
		// Iterator initialisieren
		Iterator<Rueckmeldung> iterator = query.list().iterator();

		// alle Rueckmeldungen loeschen
		while (iterator.hasNext()) {
			currentSession.delete((Rueckmeldung) iterator.next());
		}
	}

}
